﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.IO;

namespace TJDevHouse.BackupUtils.CopyModifiedDirs
{
	/// <summary>
	/// Provides a way to copy directories to a target location.
	/// </summary>
	/// 
	/// <remarks>
	/// <para>
	/// Will keep the directory paths intact and ensuring that the target
	/// location is completely cleared of any previous versions of the
	/// directory.
	/// </para>
	/// 
	/// <para>
	/// Is designed to be used to backup Mercurial's .hg directories.
	/// </para>
	/// </remarks>
	public class ModifiedDirectoryCopier
	{

		#region Properties
		/// <summary>
		/// Where to look for the directories to copy.
		/// </summary>
		public DirectoryInfo SourcePath { get; private set; }

		/// <summary>
		/// Where to copy the directories to.
		/// </summary>
		public DirectoryInfo TargetDirectory { get; private set; }

		/// <summary>
		/// The name of folders to move, for example Mercurial's ".hg"
		/// directories.
		/// </summary>
		public string DirectoryNameToInclude { get; private set; }

		/// <summary>
		/// The tracesource to use for logging
		/// </summary>
		public TraceSource TraceSource { get; set; }
		#endregion

		#region Constructors
		/// <summary>
		/// 
		/// </summary>
		/// <param name="source">The directory to search for matches within</param>
		/// <param name="target">The directory to copy any matches to</param>
		/// <param name="dirName">The directory name to find</param>
		public ModifiedDirectoryCopier(DirectoryInfo source, DirectoryInfo target, string dirName)
		{
			TraceSource = new TraceSource("TJDevHouse.BackupUtils.CopyModifiedDirs");

			SourcePath = source;
			TargetDirectory = target;
			DirectoryNameToInclude = dirName;

			TraceSource.TraceEvent(TraceEventType.Verbose, 7, "ModifiedDirectoryCopier created with properties: {0}, {1}, {2}", SourcePath.FullName, TargetDirectory.FullName, DirectoryNameToInclude);
		}
		#endregion

		#region Interface

		/// <summary>
		/// Executes the directory copy procedure. Returns the number of
		/// directories copied
		/// </summary>
		/// <returns></returns>
		public int PerformCopy()
		{
			if (!SourcePath.Exists)
			{
				TraceSource.TraceEvent(TraceEventType.Error, 6, "Supplied source directory does not exist: {0}", SourcePath.FullName);
				throw new DirectoryNotFoundException("Source directory does not exist");
			}

			int directoriesCopiedCount = 0;


			TraceSource.TraceEvent(TraceEventType.Verbose, 8, "Searching for directories...");
			DirectoryInfo[] directoriesToTest = SearchForMatchingDirs();
			TraceSource.TraceEvent(TraceEventType.Verbose, 9, "...search complete");

			TraceSource.TraceEvent(TraceEventType.Verbose, 10, "Found {0} directories matching search name", directoriesToTest.Length);

			foreach (DirectoryInfo curDir in directoriesToTest)
			{
				DirectoryCopyOperation dCopy = new DirectoryCopyOperation(curDir, SourcePath ,TargetDirectory);
				if (dCopy.TargetUpToDate)
				{
					TraceSource.TraceEvent(TraceEventType.Verbose, 11, "Target is up to date: {0}", dCopy.TargetDirectory.FullName);
				}
				else
				{
					TraceSource.TraceEvent(TraceEventType.Verbose, 12, "Copy required for: {0}", dCopy.TargetDirectory.FullName);


					TraceSource.TraceEvent(TraceEventType.Verbose, 13, "Copying {0} -> {1} ...", dCopy.SourceDirectory.FullName, dCopy.TargetDirectory.FullName);
					try
					{
						dCopy.PerformCopy();
						TraceSource.TraceEvent(TraceEventType.Information, 15, "Completed copying {0} -> {1} ...", dCopy.SourceDirectory.FullName, dCopy.TargetDirectory.FullName);
					}
					catch (Exception e)
					{
						TraceSource.TraceEvent(TraceEventType.Error, 14, "Failed copying {0} -> {1} because: ", dCopy.SourceDirectory.FullName, dCopy.TargetDirectory.FullName, e.ToString());
					}
					

					directoriesCopiedCount++;
				}

			}
			TraceSource.TraceEvent(TraceEventType.Verbose, 16, "Completed copying all directories");

			return directoriesCopiedCount;
		}

		/// <summary>
		/// Goes through the source directory recursively and finds all
		/// directories that match the specified directory name.
		/// </summary>
		/// <returns></returns>
		public DirectoryInfo[] SearchForMatchingDirs()
		{
			return SourcePath.GetDirectories(DirectoryNameToInclude, SearchOption.AllDirectories);
		}

		#endregion
		
	}
}
